//
//  STDComboLayer.hpp
//  STDRenderSDK
//
//  Created by 陈学明 on 2023/3/15.
//

#ifndef STDComboLayer_hpp
#define STDComboLayer_hpp

#include <stdio.h>
#include "STDBaseLayer.hpp"
#include <Effects/STDSBlendEffect.hpp>

/// 预合成层
class STDComboLayer: public STDBaseLayer {
public:
    STDComboLayer() {
        setType(STDLayerTypeCompose);
    }
    // 绘制图层->绘制效果->绘制到画布上
    void draw() override {
        // 绘制图层
        shared_ptr<STDSRenderTarget> dstFbo = nullptr;
        for (auto layer: mLayers) {
            if (layer->isVisible() == false) {
                continue;
            }
            // 绘制图层
            auto fbo = make_shared<STDSRenderTarget>(mSizeSRC.x, mSizeSRC.y);
            fbo->bindSelf();
            layer->draw();
            fbo->restore();
            
            if (dstFbo == nullptr) {
                dstFbo = fbo;
                continue;
            }
            // 绘制blend
            auto blendFbo = make_shared<STDSRenderTarget>(mSizeSRC.x, mSizeSRC.y);
            blendFbo->bindSelf();
            drawBlend(fbo->getTexture(), dstFbo->getTexture(), layer->getBlend());
            blendFbo->restore();
            dstFbo = blendFbo;
        }
        
        if (dstFbo == nullptr) {
            return;
        }
        
        // 绘制效果
        for (auto effect: effects) {
            if (effect->isVisible() == false) {
                continue;
            }
            auto fbo = make_shared<STDSRenderTarget>(mSizeSRC.x, mSizeSRC.y);
            effect->mSizeSRC = mSizeSRC;
            fbo->bindSelf();
            if (dstFbo == nullptr) {
                effect->setTexture(mTexture);
            } else {
                effect->setTexture(dstFbo->getTexture());
            }
            effect->setBodyTexture(mBodyTexture);
            effect->draw();
            fbo->restore();
            dstFbo = fbo;
        }
        
        // 绘制到目标fbo上
        if (dstFbo != nullptr) {
            drawTexture(dstFbo->getTexture());
        }
    }
    
public:
    void addLayer(shared_ptr<STDBaseLayer> layer) {
        mLayers.push_back(layer);
    }
    
    void moveLayerToFront(int layerID, int targetLayerID) {
        shared_ptr<STDBaseLayer> layer = popLayer(layerID);
        if (layer == nullptr) {
            return;
        }
        vector<shared_ptr<STDBaseLayer>>::iterator it = mLayers.begin();
        while (it != mLayers.end()) {
            if ((*it)->getId() == targetLayerID) {
                mLayers.insert(++it, layer);
                break;
            }
        }
    }
    
    void moveLayerToBack(int layerID, int targetLayerID) {
        shared_ptr<STDBaseLayer> layer = popLayer(layerID);
        if (layer == nullptr) {
            return;
        }
        
        vector<shared_ptr<STDBaseLayer>>::iterator it = mLayers.begin();
        while (it != mLayers.end()) {
            if ((*it)->getId() == targetLayerID) {
                mLayers.insert(it, layer);
                break;
            }
        }
    }
    
    void moveLayerToTop(int layerID) {
        shared_ptr<STDBaseLayer> layer = popLayer(layerID);
        if (layer == nullptr) {
            return;
        }
        mLayers.insert(mLayers.end(), layer);
    }
    
    void moveLayerToBottom(int layerID) {
        shared_ptr<STDBaseLayer> layer = popLayer(layerID);
        if (layer == nullptr) {
            return;
        }
        mLayers.insert(mLayers.begin(), layer);
    }
    
    shared_ptr<STDBaseLayer> getLayer(int layerID) {
        for (auto layer: mLayers) {
            if (layerID == layer->getId()) {
                return layer;
            }
            if (layer->getType() == STDLayerTypeCompose) {
                auto compose = dynamic_pointer_cast<STDComboLayer>(layer);
                auto templayer = compose->getLayer(layerID);
                if (templayer != nullptr) {
                    return templayer;
                }
            }
        }
        return nullptr;
    }
    
    shared_ptr<STDBaseLayer> popLayer(int layerID) {
        shared_ptr<STDBaseLayer> layer = nullptr;
        vector<shared_ptr<STDBaseLayer>>::iterator it = mLayers.begin();
        while (it != mLayers.end()) {
            if ((*it)->getId() == layerID) {
                layer = *it;
                mLayers.erase(it);
                break;
            }
            if ((*it)->getType() == STDLayerTypeCompose) {
                auto compose = dynamic_pointer_cast<STDComboLayer>(*it);
                layer = compose->popLayer(layerID);
                if (layer != nullptr) {
                    break;
                }
            }
            it++;
        }
        return layer;
    }
private:
    shared_ptr<STDSBlendEffect> getBlendEffect() {
        if (mBlendEffect == nullptr) {
            mBlendEffect = make_shared<STDSBlendEffect>();
            mBlendEffect->setContext(mContext);
        }
        return mBlendEffect;
    }
    
    void drawBlend(shared_ptr<STDSTexture> srcTex, shared_ptr<STDSTexture> dstTex, STDSBlendType blend) {
        auto effect = getBlendEffect();
        effect->setDstTex(dstTex);
        effect->setSrcTex(srcTex);
        effect->setBlendType(blend);
        effect->initGL();
        effect->draw();
        effect->unInitGL();
    }
private:
    shared_ptr<STDSBlendEffect> mBlendEffect{nullptr};
    vector<shared_ptr<STDBaseLayer>> mLayers;
};
#endif /* STDComboLayer_hpp */
